package com.yst.webplugin.annotation;

import com.yst.web.utils.JsonConverter;
import com.yst.webplugin.additional.ResultProcessor;
import com.yst.webplugin.additional.transform.TransDictUtil;
import com.yst.webplugin.component.ResultUtil;
import com.yst.webplugin.util.ReqParamsUtils;
import lombok.*;
import lombok.experimental.Accessors;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.DelegatingServerHttpResponse;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.method.ControllerAdviceBean;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.xml.ws.spi.http.HttpContext;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Objects;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class HttpInfo {
    private HttpServletRequest request;
    private HttpServletResponse response;
    private Object controller;

    public HttpInfo(HttpServletRequest request,HttpServletResponse response){
        this.response=response;
        setRequest(request);
    }

    @Getter
    private String body;

    public HttpInfo setRequest(HttpServletRequest request){
        if (!Objects.equals(request,this.request)) {
            this.request = request;
            this.body= ReqParamsUtils.getJsonString(request);
        }
        return this;
    }

    public <T> T getBodyAs(Class<T> clazz){
        return JsonConverter.getJsonConverter().parseObject(body,clazz);
    }

    @SneakyThrows
    public void writeThrowable(Throwable throwable){
        if (Objects.isNull(response)){
            return;
        }

        response.setContentType("application/json");
        response.setCharacterEncoding(request.getCharacterEncoding());
        ResultUtil.BeanMethod beanMethod=ResultUtil.getBeanMethod(throwable);
        if (Objects.nonNull(beanMethod)){
            Object writeObj=beanMethod.getMethod().invoke(beanMethod.getBean().resolveBean(),throwable);
            response.getWriter().write(JsonConverter.getJsonConverter().toJSONString(writeObj));
            return;
        }

        throw throwable;
    }

    @SneakyThrows
    public void writeResult(Object result,String contentType,String charset){
        if (Objects.isNull(response)) {
            return;
        }
        response.setContentType(contentType);
        response.setCharacterEncoding(charset);


        ControllerAdviceBean responseBodyAdvice=ResultUtil.getBeanForResult(result);
        if (Objects.nonNull(responseBodyAdvice)){
            ServerHttpResponse serverHttpResponse=new Response(response);
            ServerHttpRequest serverHttpRequest=new Request(request);
            Object wrapped=((ResponseBodyAdvice)(responseBodyAdvice.resolveBean())).beforeBodyWrite(result,
                    null,
                    null,
                    null,
                    serverHttpRequest,
                    serverHttpResponse);
            serverHttpResponse.getHeaders().forEach((key,value)->{
                response.setHeader(key,String.join(";",value));
            });
            response.getWriter().write(JsonConverter.getJsonConverter().toJSONString(wrapped));
            return;
        }

        response.getWriter().write(JsonConverter.getJsonConverter().toJSONString(result));
    }

    public void writeResult(Object result){
        writeResult(result,request.getContentType(),request.getCharacterEncoding());
    }
}
